package com.durian.base.rxhttp.param

import com.durian.base.rxhttp.RxHttp
import com.durian.base.utils.GsonUtils
import okhttp3.FormBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File

/**
 * 说明：RxPostParam
 * <p/>
 * 作者：Fanly
 * <p/>
 * 类型：Class
 * <p/>
 * 时间：2020/04/24 20:42
 * <p/>
 * 版本：version 1.0
 */
class RxPostParam(url: String, method: Method) : RxBaseParam<RxPostParam>(url, method), IFileParam<RxPostParam>, IJsonParam<RxPostParam> {

    private val fileBuilder by lazy {
        mutableListOf<KeyFilePair>()
    }
    private var useJsonParam = false
    private var useJsonParamData = ""

    override fun getRequestBody(): RequestBody? {
        return if (useJsonParam || useJsonParamData.isNotEmpty()) {
            createJsonBody()
        } else if (fileBuilder.isNotEmpty()) {
            createFormBodyWithFiles()
        } else {
            createFormBody()
        }
    }

    override fun buildRequest(): Request {
        if (isAssemblyEnable) {
            RxHttp.getParamAssembly()?.invoke(this)
        }
        mutableMapOf<String,String>().let {map ->
            paramsBuilder.forEach { map[it.key] = it.value.toString() }
            RxHttp.getRequestBodyHook()?.invoke(this,map)
        }
        val builder =  requestBuilder.headers(headersBuilder.build())
                .url(RxHttp.getHttpUrl(url))
        when{
            method.isPost() ->{
                builder.post(getRequestBody()!!)
            }
            method.isPut() ->{
                builder.put(getRequestBody()!!)
            }
            method.isPatch()->{
                builder.patch(getRequestBody()!!)
            }
            method.isDelete()->{
                builder.delete(getRequestBody()!!)
            }
            else ->{
                throw IllegalArgumentException("This method(${method}) not support!!!")
            }
        }
        return builder.build()
    }

    private fun createFormBodyWithFiles(): RequestBody? {
        val builder = MultipartBody.Builder()
        builder.setType(MultipartBody.FORM)
        paramsBuilder.forEach {
            builder.addFormDataPart(it.key, it.value.toString())
        }
        fileBuilder.forEach {
            if (it.file.isFile && it.file.exists()) {
                builder.addFormDataPart(it.key, it.file.name, it.getRequestBody())
            }
        }
        return builder.build()
    }

    private fun createJsonBody(): RequestBody? {
        val json = if (useJsonParamData.isNotEmpty()){
            useJsonParamData
        }else{
            val map = mutableMapOf<String,String>()
            paramsBuilder.forEach { map[it.key] = it.value.toString() }
            GsonUtils.toJson(map)
        }
        return json.toRequestBody("application/json; charset=UTF-8".toMediaTypeOrNull())
    }

    private fun createFormBody(): RequestBody? {
        val builder = FormBody.Builder()
        paramsBuilder.forEach {
            if (it.isEncoded) {
                builder.addEncoded(it.key, it.value.toString())
            } else {
                builder.add(it.key, it.value.toString())
            }
        }
        return builder.build()
    }

    override fun addFile(key: String, filePath: String, body: RequestBody?): RxPostParam {
        val pair = KeyFilePair(key, File(filePath), body)
        if (pair.checkFile()) {
            fileBuilder.add(pair)
        }
        return this
    }

    override fun addFile(key: String, file: File, body: RequestBody?): RxPostParam {
        return addFile(key, file.absolutePath, body)
    }

    override fun setJsonParams(enable: Boolean, data: String?): RxPostParam {
        useJsonParam = enable
        useJsonParamData = data ?: ""
        return this
    }

}